package com.doctcloud.common.core.utils.bean;

import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * 通用 Do/Vo 转换工具类
 * 支持任意 Do 与 Vo 之间的转换，兼顾默认自动拷贝和自定义字段处理
 * @param <DO> 数据层实体（如 DeptDictDo）
 * @param <VO> 视图/存储层实体（如 DeptDictVo）
 */
public class CommonDoVoConverter<DO, VO> {

    // ==================== 单个对象转换 ====================
    /**
     * 单个 Do 转 Vo（仅自动拷贝字段名/类型一致的属性）
     * @param doObj 源 Do 对象
     * @param voClass 目标 Vo 的 Class（如 DeptDictVo.class）
     * @return 转换后的 Vo 对象
     */
    public VO doToVo(DO doObj, Class<VO> voClass) {
        if (doObj == null || voClass == null) {
            return null; // 避免空指针
        }

        try {
            // 1. 反射创建 Vo 实例（需 Vo 有默认无参构造器，常规实体类都满足）
            VO voObj = voClass.getDeclaredConstructor().newInstance();
            // 2. 自动拷贝字段名/类型一致的属性（Spring BeanUtils 核心能力）
            BeanUtils.copyProperties(doObj, voObj);
            return voObj;
        } catch (Exception e) {
            throw new RuntimeException("Do 转 Vo 失败：" + doObj.getClass().getSimpleName() + " → " + voClass.getSimpleName(), e);
        }
    }

    /**
     * 单个 Do 转 Vo（支持自定义字段处理，解决字段名不一致、特殊类型转换）
     * @param doObj 源 Do 对象
     * @param voClass 目标 Vo 的 Class
     * @param customHandler 自定义转换逻辑（如处理大小写差异、类型转换）
     * @return 转换后的 Vo 对象
     */
    public VO doToVo(DO doObj, Class<VO> voClass, Consumer<VoDoContext<DO, VO>> customHandler) {
        // 1. 先执行默认自动拷贝
        VO voObj = doToVo(doObj, voClass);
        if (voObj == null || customHandler == null) {
            return voObj;
        }

        // 2. 执行自定义转换逻辑（传入 Do 和 Vo 上下文，方便处理特殊字段）
        customHandler.accept(new VoDoContext<>(doObj, voObj));
        return voObj;
    }

    // ==================== 批量列表转换 ====================
    /**
     * Do 列表转 Vo 列表（仅自动拷贝）
     * @param doList 源 Do 列表
     * @param voClass 目标 Vo 的 Class
     * @return 转换后的 Vo 列表（空列表返回空集合，不返回 null）
     */
    public List<VO> doListToVoList(List<DO> doList, Class<VO> voClass) {
        if (CollectionUtils.isEmpty(doList)) {
            return new ArrayList<>();
        }

        List<VO> voList = new ArrayList<>(doList.size());
        for (DO doObj : doList) {
            voList.add(doToVo(doObj, voClass));
        }
        return voList;
    }

    /**
     * Do 列表转 Vo 列表（支持自定义字段处理）
     * @param doList 源 Do 列表
     * @param voClass 目标 Vo 的 Class
     * @param customHandler 每个对象的自定义转换逻辑
     * @return 转换后的 Vo 列表
     */
    public List<VO> doListToVoList(List<DO> doList, Class<VO> voClass, Consumer<VoDoContext<DO, VO>> customHandler) {
        if (CollectionUtils.isEmpty(doList)) {
            return new ArrayList<>();
        }

        List<VO> voList = new ArrayList<>(doList.size());
        for (DO doObj : doList) {
            voList.add(doToVo(doObj, voClass, customHandler));
        }
        return voList;
    }

    // ==================== 反向转换（Vo 转 Do，按需使用） ====================
    public DO voToDo(VO voObj, Class<DO> doClass) {
        if (voObj == null || doClass == null) {
            return null;
        }

        try {
            DO doObj = doClass.getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(voObj, doObj);
            return doObj;
        } catch (Exception e) {
            throw new RuntimeException("Vo 转 Do 失败：" + voObj.getClass().getSimpleName() + " → " + doClass.getSimpleName(), e);
        }
    }

    public DO voToDo(VO voObj, Class<DO> doClass, Consumer<VoDoContext<DO, VO>> customHandler) {
        DO doObj = voToDo(voObj, doClass);
        if (doObj == null || customHandler == null) {
            return doObj;
        }
        // 注意：反向转换时，上下文的 Do/Vo 顺序不变，自定义处理时需注意
        customHandler.accept(new VoDoContext<>(doObj, voObj));
        return doObj;
    }

    // ==================== 上下文类：传递 Do 和 Vo 对象，方便自定义处理 ====================
    public static class VoDoContext<DO, VO> {
        private final DO doObj;
        private final VO voObj;

        public VoDoContext(DO doObj, VO voObj) {
            this.doObj = doObj;
            this.voObj = voObj;
        }

        // Getter 方法，供自定义处理时获取 Do/Vo 对象
        public DO getDoObj() {
            return doObj;
        }

        public VO getVoObj() {
            return voObj;
        }
    }

    // ==================== 静态工厂方法：快速创建转换器实例 ====================
    /**
     * 快速创建通用转换器实例（无需 new，更简洁）
     * 示例：CommonDoVoConverter<DeptDictDo, DeptDictVo> converter = CommonDoVoConverter.create();
     */
    public static <DO, VO> CommonDoVoConverter<DO, VO> create() {
        return new CommonDoVoConverter<>();
    }
}